package com.xcity.game.pet;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.xcity.db.entity.Player;
import com.xcity.game.common.Cause;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.MessageConst;
import com.xcity.game.common.PlayerPool;
import com.xcity.game.item.ItemTemplate;
import com.xcity.game.mail.MailService;
import com.xcity.game.pet.template.PetTemplate;
import com.xcity.pomelo.push.SyncPush;
import com.xcity.pomelo.push.msg.TipPush;
import com.xcity.pomelo.push.sync.MapSync;
import com.xcity.util.IdUtils;

import naga.x.App;
import naga.x.game.template.TemplateService;
import naga.x.game.time.TimeUpdater;
import naga.x.util.TimeUtils;

public class Pet {

	@JSONField(name = "0")
	protected long id;
	@JSONField(name = "1")
	protected int templateId;
	@JSONField(name = "2")
	protected int level;
	@JSONField(name = "3")
	protected int spirit;
	@JSONField(name = "4")
	protected State state;
	@JSONField(name = "5")
	protected List<PetSkill> skills;
	@JSONField(name = "6")
	protected long lastLostSpiritTime; // 上一次掉精神时间
//	@JSONField(name = "7")
//	protected long lastWashTime;
	@JSONField(name = "8")
	protected long lastPlayTime; // 上次玩耍时间
	@JSONField(name = "9")
	protected int todayPlayTimes; // 今日已玩耍总次数
	@JSONField(name = "10")
	protected long createTime;
	@JSONField(name = "11")
	protected long lastAutoFeedTime; // 上一次自动喂食时间
	@JSONField(name = "12")
	protected int lastWashDay; // 上次洗澡时间
	protected long nextWashTime; // 下次可洗澡时间(不用持久化)
	
	@JSONField(serialize = false)
	protected PetTemplate template;
	
	protected PetManager vm;
	
	public static final int LOST_SPIRIT_INTERVAL = (int) TimeUnit.HOURS.toMillis(1);
	// 超过24小时精神低于1则逃跑
	public static final int ESCAPE_SPIRIT = 1;
	public static final int ESCAPE_CD = (int) TimeUnit.DAYS.toMillis(1);
//	// 洗澡cd
//	public static final int WASH_CD = (int) TimeUnit.DAYS.toMillis(1);
	
	public static final int PLAY_CD = (int) TimeUnit.MINUTES.toMillis(30);
	public static final int PLAY_MAX_TIMES_PER_DAY = 5;
	public static final int LEVEL_UP_CD = (int) TimeUnit.DAYS.toMillis(1);
	public static final int MAX_LEVEL = 20;
	// 被撕咬状态持续时间
	public static final int SKILL_BIT_DURATION = (int) TimeUnit.HOURS.toMillis(1);
	// 自动喂食精神百分比
	public static final int AUTO_FEED_SPIRIT_PERCENT = 70;
	public static final int AUTO_FEED_CD = (int) TimeUnit.MINUTES.toMillis(30);
	public static final int AUTO_FEED_VIP_LEVEL = 5;
	
	protected static final Random RND = new Random();
	protected static final Logger LOG = PetService.LOG;
	
	public static enum State {
		FREE, // 休息状态
		WORK; // 工作状态
		public static final State codeOf(int code) {
			switch (code) {
				case 0: return FREE;
				case 1: return WORK;
				default : return null;
			}
		}
	}
	
	public Pet() {}
	
	public Pet(PetManager container, int templateId) {
		this.vm = container;
		this.id = IdUtils.nextPetId();
		this.templateId = templateId;
		this.level = 1;
		this.spirit = getTemplate().getSpirit();
		this.state = State.FREE;
		this.skills = new ArrayList<PetSkill>(3);
		this.skills.add(new PetSkill(getTemplate().getBornSkill(), this));
		this.lastLostSpiritTime = TimeUpdater.getInstance().now();
		this.createTime = TimeUpdater.getInstance().now();
		tryGet2ndSkill();
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public int getTemplateId() {
		return templateId;
	}

	public void setTemplateId(int templateId) {
		this.templateId = templateId;
	}

	public int getLevel() {
		return level;
	}

	public void setLevel(int level) {
		this.level = level;
	}

	public int getSpirit() {
		return spirit;
	}

	public void setSpirit(int spirit) {
		this.spirit = spirit;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public List<PetSkill> getSkills() {
		return skills;
	}

	public void setSkills(List<PetSkill> skills) {
		this.skills = skills;
		if (skills != null) {
			for (PetSkill ps : skills) {
				ps.pet = this;
			}
		}
	}

	public long getLastLostSpiritTime() {
		return lastLostSpiritTime;
	}

	public void setLastLostSpiritTime(long lastLostSpiritTime) {
		this.lastLostSpiritTime = lastLostSpiritTime;
	}

	public int getLastWashDay() {
		return lastWashDay;
	}

	public void setLastWashDay(int lastWashDay) {
		this.lastWashDay = lastWashDay;
		// 重新计算下次可洗澡时间
		calcNextWashTime();
	}

	public long getLastPlayTime() {
		return lastPlayTime;
	}

	public void setLastPlayTime(long lastPlayTime) {
		this.lastPlayTime = lastPlayTime;
	}

	public int getTodayPlayTimes() {
		return todayPlayTimes;
	}

	public void setTodayPlayTimes(int todayPlayTimes) {
		this.todayPlayTimes = todayPlayTimes;
	}

	public long getCreateTime() {
		return createTime;
	}

	public void setCreateTime(long createTime) {
		this.createTime = createTime;
	}

	public long getLastAutoFeedTime() {
		return lastAutoFeedTime;
	}

	public void setLastAutoFeedTime(long lastAutoFeedTime) {
		this.lastAutoFeedTime = lastAutoFeedTime;
	}

	public PetTemplate getTemplate() {
		return template != null ? template : (template = App.getApp().getServiceManager().get(TemplateService.class).get(PetTemplate.class, templateId));
	}

	public void setTemplate(PetTemplate template) {
		this.template = template;
	}
	
	public boolean addSpirit(int val, String cause) {
		if (val <= 0) {
			return false;
		}
		int MAX_SPIRIT = getTemplate().getSpirit();
		if (spirit < MAX_SPIRIT) {
			int oldVal = spirit;
			spirit += val;
			if (spirit > MAX_SPIRIT) {
				spirit = MAX_SPIRIT;
			}
			if (oldVal <= ESCAPE_SPIRIT && spirit > ESCAPE_SPIRIT) {
				// 宠物精神低于逃跑值时增加精神，需重置上一次掉精神时间，避免时间差过长导致立刻扣掉精神 @see update
				lastLostSpiritTime = TimeUpdater.getInstance().now();
			}
			Player player = vm.getOwner();
			if (state == State.WORK) {
				player.send(new MapSync(SyncPush.SYNC_PET_SPIRIT, id, new int[] { spirit, MAX_SPIRIT }));
			}
			LOG.info("[PET ADDSPIRIT]ID[{}]PET[{}]PETTID[{}]OLD[{}]NEW[{}]CAUSE[{}]", player.getId(), id, templateId, oldVal, spirit, cause);
			return true;
		}
		return false;
	}
	
	public boolean decSpirit(int val, String cause) {
		if (val <= 0 || spirit == 0) {
			return false;
		}
		int oldVal = spirit;
		spirit -= val;
		if (spirit < 0) {
			spirit = 0;
		}
		Player player = vm.getOwner();
		if (state == State.WORK) {
			player.send(new MapSync(SyncPush.SYNC_PET_SPIRIT, id, new int[] { spirit, getTemplate().getSpirit() }));
		}
		LOG.info("[PET DECSPIRIT]ID[{}]PET[{}]PETTID[{}]OLD[{}]NEW[{}]CAUSE[{}]", player.getId(), id, templateId, oldVal, spirit, cause);
		return true;
	}

	public boolean update() {
		Player player;
		int spirit70percent;
		if ((player = vm.getOwner()) != null
				&& player.isOnline()
				&& player.getVipLvl() >= AUTO_FEED_VIP_LEVEL
				&& TimeUpdater.getInstance().now() - lastAutoFeedTime > AUTO_FEED_CD
				&& spirit < (spirit70percent = getTemplate().getSpirit() * AUTO_FEED_SPIRIT_PERCENT / GameStaticConfig.percentBase)) {
			// 自动喂食
			lastAutoFeedTime = TimeUpdater.getInstance().now();
			List<ItemTemplate> foods = App.getApp().getServiceManager().get(PetService.class).getFoods();
			for (int i = 0; i < foods.size(); i++) {
				int needFeedVal = spirit70percent - spirit;
				if (needFeedVal <= 0) { // 已将精神值喂到70%
					break;
				}
				ItemTemplate food = foods.get(i);
				int val = food.getParameter(0); // 该狗粮可恢复精神值
				if (val <= 0) { // 不可能,除非配置错误
					continue;
				}
				int c = player.getBag().countOf(food.getId());
				if (c > 0) {
					int n = (needFeedVal + val - 1) / val; // 理论上需要该狗粮数量
					c = c > n ? n : c; // 修正实际可喂食的数量
					boolean succ = player.getBag().removeItem(food.getId(), c, Cause.PET_AUTO_FEED);
					if (succ) {
						addSpirit(val * c, Cause.PET_AUTO_FEED);
					}
				}
			}
			if (spirit < spirit70percent) {
				// 没喂足(狗粮不够)则需要提醒玩家
				if (player.getPool().getIntValue(PlayerPool.PROPERTY_LAST_PROMPT_PET_FOOD_LACK_DAY) != TimeUpdater.getInstance().today()) {
					player.poolSet(PlayerPool.PROPERTY_LAST_PROMPT_PET_FOOD_LACK_DAY, TimeUpdater.getInstance().today());
					App.getApp().getServiceManager().get(MailService.class).sendSystemMail(player.getId(), MessageConst.PET_FOOD_LACK_MAIL_TITLE, MessageConst.PET_FOOD_LACK_MAIL_CONTENT);
					player.send(new TipPush(MessageConst.PET_FOOD_LACK_TIP));
				}
			}
		}
		if (spirit <= ESCAPE_SPIRIT) {
			if (TimeUpdater.getInstance().now() - lastLostSpiritTime >= ESCAPE_CD) {
				return false;
			}
			return true;
		}
		long elapse;
		if ((elapse = TimeUpdater.getInstance().now() - lastLostSpiritTime) >= LOST_SPIRIT_INTERVAL) {
			lastLostSpiritTime = TimeUpdater.getInstance().now();
			int lost = (int) (getTemplate().getLostSpirit() * elapse / LOST_SPIRIT_INTERVAL);
			decSpirit(lost, Cause.AUTO);
		}
		return true;
	}
	
	/**
	 * 尝试领悟第二个技能
	 */
	private void tryGet2ndSkill() {
		if (skills.size() > 1) {
			return;
		}
		if (RND.nextInt(GameStaticConfig.defaultChanceBase) < getTemplate().getSecondSkillProbability()) {
			PetSkill skill = new PetSkill(getTemplate().getSecondSkill(), this);
			skills.add(skill);
			LOG.info("[PET GET2NDSKILL]ID[{}]PET[{}]PETTID[{}]LEVEL[{}]SKILL[{}]", vm.getOwner().getId(), id, templateId, level, skill.getId());
		}
	}
	
	public void addLevel(int val, String cause) {
		int oldLvl = level;
		if (oldLvl >= MAX_LEVEL) {
			return;
		}
		level += val;
		if (level > MAX_LEVEL) {
			level = MAX_LEVEL;
		}
		LOG.info("[PET LVLUP]ID[{}]PET[{}]PETTID[{}]OLDLVL[{}]LEVEL[{}]CAUSE[{}]", vm.getOwner().getId(), id, templateId, oldLvl, level, cause);
		addSkillLevel(val, Cause.AUTO);
		tryGet2ndSkill();
	}
	
	public void addSkillLevel(int val, String cause) {
		for (int i = 0, size = skills.size(); i < size; i++) {
			PetSkill skill = skills.get(i);
			skill.addLevel(val, cause);
		}
	}
	
	public PetSkill getSkillByType(int type) {
		for (int i = skills.size() - 1; i >= 0; i--) {
			PetSkill skill = skills.get(i);
			if (skill.getTemplate().getType() == type) {
				return skill;
			}
		}
		return null;
	}
	
	@JSONField(serialize = false)
	public int getWashCD() {
		if (getLastWashDay() == TimeUpdater.getInstance().today()) {
			if (nextWashTime == 0L) {
				calcNextWashTime();
			}
			long cd = nextWashTime - TimeUpdater.getInstance().now();
			return cd < 0 ? 0 : (int) cd;
		}
		return 0;
	}
	
	protected void calcNextWashTime() {
		nextWashTime = TimeUtils.getTodayZeroTime();
		if (lastWashDay == TimeUpdater.getInstance().today()) {
			nextWashTime += TimeUnit.DAYS.toMillis(1);
		}
	}
	
	@JSONField(serialize = false)
	public int getPlayCD() {
		if (getLastPlayTime() == 0L) {
			return 0;
		}
		long cd = PLAY_CD + getLastPlayTime() - TimeUpdater.getInstance().now();
		return cd < 0 ? 0 : (int) cd;
	}
	
	/**
	 * 获取当前可升级的经验点数(每24小时累积1点)
	 * @return
	 */
	@JSONField(serialize = false)
	public int getExp() {
		int exp;
		if (level < MAX_LEVEL
				&& (exp = (int) ((TimeUpdater.getInstance().now() - createTime) / LEVEL_UP_CD) + 1 - level) > 0) {
			return exp;
		}
		return 0;
	}

	@Override
	public String toString() {
		return JSON.toJSONString(this);
	}

}
